package top.knos.od.config.dataSource;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

@Configuration
@EnableTransactionManagement
@EntityScan({"top.knos.od.his"})
@EnableJpaRepositories(
        basePackages = "top.knos.od.his",
        entityManagerFactoryRef = "hisEntityManagerFactory",
        transactionManagerRef = "hisTransactionManager"
)
public class HisDataBaseConfig {

    @Value("${spring.jpa.his.hibernate.dialect}")
    private String dialect;

    /**
     * 扫描spring.datasource.his开头的配置信息
     *
     * @return 数据源配置信息
     */
    @Bean(name = "hisDataSourceProperties")
    @ConfigurationProperties(prefix = "spring.datasource.his")
    public DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }

    /**
     * 获取从库数据源对象
     *
     * @param properties 注入名为hisDataSourceProperties的bean
     * @return 数据源对象
     */
    @Bean(name = "hisDataSource")
    public DataSource dataSource(@Qualifier("hisDataSourceProperties") DataSourceProperties properties) {
        return properties.initializeDataSourceBuilder().build();
    }

    /**
     * 该方法仅在需要使用JdbcTemplate对象时选用
     *
     * @param dataSource 注入名为hisDataSource的bean
     * @return 数据源JdbcTemplate对象
     */
    @Bean(name = "hisJdbcTemplate")
    public JdbcTemplate jdbcTemplate(@Qualifier("hisDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    /**
     * 扫描spring.jpa.his开头的配置信息
     *
     * @return jpa配置信息
     */
    @Bean(name = "hisJpaProperties")
    @ConfigurationProperties(prefix = "spring.jpa.his")
    public JpaProperties jpaProperties() {
        return new JpaProperties();
    }

    @Bean(name = "hisHibernateProperties")
    @ConfigurationProperties(prefix = "spring.jpa.his.hibernate")
    public HibernateProperties hibernateProperties() {
        return new HibernateProperties();
    }

    /**
     * 获取从库实体管理工厂对象
     *
     * @param hisDataSource 注入名为hisDataSource的数据源
     * @param jpaProperties 注入名为hisJpaProperties的jpa配置信息
     * @param builder       注入EntityManagerFactoryBuilder
     * @return 实体管理工厂对象
     */
    @Bean(name = "hisEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            @Qualifier("hisDataSource") DataSource hisDataSource
            , @Qualifier("hisJpaProperties") JpaProperties jpaProperties,
            @Qualifier("hisHibernateProperties") HibernateProperties hibernateProperties,
            EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(hisDataSource)
                .properties(jpaProperties.getProperties())
                //.properties(Map.of("ddl-auto", hibernateProperties.getDdlAuto()))
                .properties(getVendorProperties(jpaProperties, hibernateProperties))
                .properties(Collections.singletonMap("hibernate.hbm2ddl.auto", "none"))
                .packages("top.knos.od.his")
                .persistenceUnit("hisPersistenceUnit")
                .build();
    }

    private Map<String, Object> getVendorProperties(JpaProperties jpaProperties,
                                                    HibernateProperties hibernateProperties) {
        Map<String, String> map = new HashMap<>();
        map.put("hibernate.dialect", dialect);// 设置对应的数据库方言
        jpaProperties.setProperties(map);
        return hibernateProperties.determineHibernateProperties(
                jpaProperties.getProperties(), new HibernateSettings());
    }

    /**
     * 获取实体管理对象
     *
     * @param factory 注入名为hisEntityManagerFactory的bean
     * @return 实体管理对象
     */
    @Bean(name = "hisEntityManager")
    public EntityManager entityManager(@Qualifier("hisEntityManagerFactory") EntityManagerFactory factory) {
        return factory.createEntityManager();
    }

    /**
     * 获取从库事务管理对象
     *
     * @param factory 注入名为hisEntityManagerFactory的bean
     * @return 事务管理对象
     */
    @Bean(name = "hisTransactionManager")
    public PlatformTransactionManager transactionManager(@Qualifier("hisEntityManagerFactory") EntityManagerFactory factory) {
        return new JpaTransactionManager(factory);
    }
}
